import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ClassLoaderUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.benjaminwan.ocrlibrary.OcrResult;
import io.github.mymonstercat.Model;
import io.github.mymonstercat.ocr.InferenceEngine;
import io.github.mymonstercat.ocr.config.HardwareConfig;
import io.github.mymonstercat.ocr.config.ParamConfig;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import utils.ImageFilter;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;

@Slf4j
public class OcrTestDemo {


    private static int TARGET_BRIGHTNESS = 260; // 300;
    private static int TARGET_DIFFERENCE_VALUE = 15;

    public static final String IDN_CHARS = "0123456789Xx";

    @Test
    void ocrDemo() {

        log.info(tempDir);

    }



    String tempDir = Paths.get(System.getProperty("user.home"))
        .resolve("Desktop").toString() + File.separator;



    @Test
    public void execOcr() throws IOException {

        // 配置参数
        ParamConfig paramConfig = ParamConfig.getDefaultConfig();
        // 当文本不是水平排列时，启用角度检测可以更准确地识别文本内容。
        paramConfig.setDoAngle(true);
        // 文本的最大倾斜角度
        paramConfig.setMostAngle(true);

        HardwareConfig onnxConfig = HardwareConfig.getOnnxConfig();
        onnxConfig.setNumThread(3);

        // 引擎初始化
        InferenceEngine ocrEngine = InferenceEngine.getInstance(Model.ONNX_PPOCR_V3,onnxConfig);



        // 读取资源文件
        String resPath = getResourcePath("/images/idc2.png");
        // 读取的资源文件不存在



        // 该方法会根据图像文件的格式自动选择最适合的内部表示形式。这意味着读入的图像可能不会总是以 TYPE_3BYTE_BGR 的形式存储，而是根据文件格式和解码器的实现可能采用不同的颜色模型，例如 TYPE_INT_ARGB 或 TYPE_INT_RGB 等
        // 例如，PNG 和 GIF 格式的图像通常包含 Alpha 通道，所以它们会被解码为支持透明度的类型，如 TYPE_INT_ARGB。而 JPEG 图像通常是不透明的，可能会被解码为 TYPE_3BYTE_BGR 或者 TYPE_INT_RGB。

        // 必须转换为3字节RGB
        BufferedImage image = ImageFilter.cloneImage(ImageIO.read(new File(resPath)));




        // 图像预处理
        //缩放到真实身份证大小（标准尺寸）
        image = ImageFilter.imageScale(image, 673, 425);

        // 临时名
        String randStr = RandomUtil.randomString(6);

        // 存储
        saveImage(image, tempDir + randStr + ".jpg");

        // 剪切图片：姓名
        BufferedImage nameImage = ImageFilter.subImage(image, 100, 40, 200, 70);
        // 处理图像
        nameImage = resolveImage(nameImage);

        // 剪切图片：身份证号
        BufferedImage idnImage = ImageFilter.subImage(image, 200, image.getHeight() - 85, 450, 75);
        idnImage = resolveImage(idnImage);

        // 让原图失效
        image = null;


        String namePath = tempDir + randStr + "-姓名" + ".jpg";
        // 存储
        File nameFile = saveImage(nameImage, namePath);
        // 执行识别
        String name = execOcr(ocrEngine, paramConfig, namePath);
        log.info("姓名为：{}", name);


        String idnPath = tempDir + randStr + "-身份证号" + ".jpg";
        // 存储
        File idnFile = saveImage(idnImage, idnPath);
        // 执行识别
        String idn = execOcr(ocrEngine, paramConfig, idnPath);
        // 过滤
        idn = StrUtil.filter(idn, c -> StrUtil.contains(IDN_CHARS, c));
        // 断言
        boolean isValid = IdcardUtil.isValidCard18(idn);
        if (!isValid) {
            log.warn("解析的身份证号不合法：{}", idn);
        }
        else log.info("身份证号为：{}", idn);

        // 删除临时文件
//        nameFile.delete();
//        idnFile.delete();
        // 程序停止时删除
//        nameFile.deleteOnExit();
//        return Result.success(name + "：" + idn);

        log.info("临时随机名：{}",randStr);

    }



    private BufferedImage resolveImage(BufferedImage image) {
        // 增大对比度
        image = ImageFilter.imageContrast(image, 1.2f);
        // 应用RGB差异滤镜
        image = ImageFilter.imageRGBDifferenceFilter(image, TARGET_DIFFERENCE_VALUE, null);
        // 转为灰度图像
        image = ImageFilter.convertImageToGrayScale(image);

        // 当前亮度
        int currentBrightness = ImageFilter.imageBrightness(image);
        log.info("当前图片亮度：{}", image);
        // 亮度修正
        int fixedBrightness = TARGET_BRIGHTNESS - currentBrightness;
        if (fixedBrightness != 0) {
            // 提亮（去除亮色背景中的灰色杂线）
            image = ImageFilter.imageBrightness(image, fixedBrightness);
            log.info("修正后的亮度：{}", fixedBrightness);
        }

        return image;
    }


    private File saveImage(BufferedImage bufferedImage, String path) {
        File imageFile = new File(path);
        try {
            ImageIO.write(bufferedImage, "jpg",
                    IoUtil.toBuffered(FileUtil.getOutputStream(imageFile)));
        } catch (IOException e) {
            log.error("图片保存失败：" + path);
        }
        return imageFile;
    }


    private String execOcr(InferenceEngine engine, ParamConfig paramConfig, String imagePath) {
        // 开始识别
        long stp = System.currentTimeMillis();
        OcrResult ocrResult = engine.runOcr(imagePath, paramConfig);
        log.info("识别耗时：{}毫秒", System.currentTimeMillis() - stp);

        return ocrResult.getStrRes().trim();
    }







    private static String getResourcePath(String path) {
        // 不用File的话，路径类似于linux：/C:/Users/...
        return new File(OcrTestDemo.class.getResource(path).getFile()).toString();
    }


    //    @SneakyThrows
    private static String getResourcePath2(String path) {
        // 获取当前应用程序中的，当前线程的上下文类加载器
        return Thread.currentThread().getContextClassLoader().getResource(path).getPath();
    }
    private static String getResourceDir() {
        return ClassLoaderUtil.getClassLoader()
                .getResource("").getPath();
    }


    @Test
    void resDir() {
        log.info(getResourceDir());
        log.info(getResourcePath(""));
        log.info(getResourcePath2(""));
    }
}
